package com.ease.core.components {
   import com.ease.core.components.menus.TabMenu;
   import com.ease.core.events.DockingEvent;
   import com.ease.core.layout.BorderLayout;
   import com.ease.core.layout.BorderLayoutPosition;
   import com.ease.core.managers.PerspectiveManager;
   import com.ease.core.managers.ViewManager;
   import com.ease.component.events.AdvancedMouseEvent;

   import flash.display.DisplayObject;
   import flash.display.DisplayObjectContainer;
   import flash.events.Event;
   import flash.events.MouseEvent;
   import flash.geom.Point;
   import flash.geom.Rectangle;

   import mx.binding.utils.BindingUtils;
   import mx.containers.Canvas;
   import mx.containers.HBox;
   import mx.containers.TabNavigator;
   import mx.controls.Button;
   import mx.core.EdgeMetrics;
   import mx.core.ScrollPolicy;
   import mx.events.DragEvent;
   import mx.events.FlexEvent;
   import mx.events.IndexChangedEvent;
   import mx.events.ItemClickEvent;
   import mx.managers.DragManager;
   import mx.managers.PopUpManager;

   public class ViewWindow extends TabNavigator implements DockingWindow {
      public static const MINIMIZED_HEIGHT:Number = 22;
      public static const WINDOW_STATE_DEFAULT:Number = -1;
      public static const WINDOW_STATE_MINIMIZED:Number = 0;
      public static const WINDOW_STATE_MAXIMIZED:Number = 1;

      public var windowState:Number; // Corresponds to one of the WINDOW_STATE variables.
      public var index:Number; // Index within the layout.

      private var _dropEnabled:Boolean = true;

      private var _dragEnabled:Boolean = true;

      public var borderLayout:String = BorderLayout.CENTER;

      public var borderLayoutPosition:BorderLayoutPosition;

      /** child component */
      protected var titleBar:ViewWindowBar;

      protected var canvas:Canvas;

      private var _originalWidth:Number = -1;
      public function get originalWidth():Number {
         return _originalWidth;
      }
      public function set originalWidth(value:Number):void {
         _originalWidth = value;
      }

      private var _originalHeight:Number = -1;
      public function get originalHeight():Number {
         return _originalHeight;
      }
      public function set originalHeight(value:Number):void {
         _originalHeight = value;
      }

      private var _originalParent:DisplayObjectContainer = null;
      public function get originalParent():DisplayObjectContainer {
         return _originalParent;
      }
      public function set originalParent(value:DisplayObjectContainer):void {
         _originalParent = value;
      }

      public var originalX:Number;
      public var originalY:Number;
      public var targetWidth:Number = -1;
      public var targetHeight:Number = -1;
      public var actived:Boolean = false;

      protected var minimizeButton:Button;

      protected var maximizeButton:Button;

      protected var viewActionBar:HBox;

      protected var dockProxy:Canvas;

      private var _showControls:Boolean;
      private var _showControlsChanged:Boolean;

      private var _maximize:Boolean;
      private var _maximizeChanged:Boolean;

      private var _menuCav:Canvas;
      private var _tabMenu:TabMenu;

      private var _selectedViews:Array = [];
      private var _lastSelectedView:* = -1;

      public function ViewWindow() {
         super();

         windowState = WINDOW_STATE_DEFAULT;
         horizontalScrollPolicy = "off";

         addEventListener(DockingEvent.CLOSED, onViewClosed);

         addEventListener(DragEvent.DRAG_OVER, onDragOver);
         addEventListener(DragEvent.DRAG_ENTER, onDragEnter);
         addEventListener(DragEvent.DRAG_EXIT, onDragExit);
         addEventListener(DragEvent.DRAG_DROP, onDragDrop);

         addEventListener(IndexChangedEvent.CHANGE, tabChangedEvent);
         addEventListener(FlexEvent.VALUE_COMMIT, onValueCommited);
         addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
         addEventListener(AdvancedMouseEvent.RIGHT_MOUSE_DOWN, onMenuSelectedHandler);
         addEventListener(TabMenu.EVENT_CLOSE, onClose);
         addEventListener(TabMenu.EVENT_CLOSE_OTHERS, onCloseOthers);
         addEventListener(TabMenu.EVENT_CLOSE_ALL, onCloseAll);

         percentWidth = percentHeight = 100;
         styleName = "viewWindow";

         doubleClickEnabled = true;
         focusEnabled = true;

         BindingUtils.bindSetter(onAcitiveViewChange, ViewManager.getInstance(), "activeViewWindow");
      }

      public function onAcitiveViewChange(value:String):void {
         if (!value) {
            return;
         }
         actived = value == uid;
         if (actived) {
            setStyle("backgroundColor", "0x9ABAE9");
         }
         else {
            setStyle("backgroundColor", "0xF0F0F0");
         }
         if (tabBar) {
            for each (var tab:Button in tabBar.getChildren()) {
               tab.styleChanged("selectedUpSkin");
            }
         }
      }

      protected function onMenuSelectedHandler(event:MouseEvent):void {
         var item:DisplayObject = getItemUnderMouse(event.stageX, event.stageY, tabBar.getChildren());
         if (item) {
            if (item is ViewTab || item.parent is ViewTab) {
               var tab:ViewTab = (item is ViewTab)? ViewTab(item) : (item.parent is ViewTab)? ViewTab(item.parent): null;
               if (tab) {
                  selectedChild = tab.data as DockingView;
                  _tabMenu.selectedItems = [selectedChild];
                  return;
               }
            }
         }
         _tabMenu.selectedItems = [];
      }

      public function getItemUnderMouse(x:Number, y:Number, items:Array):* {
         for each(var item:* in items) {
            if (item.hitTestPoint(x, y)) {
               return item;
            }
         }

         return null;
      }

      public function clearOriginalSize():void {
         originalParent = null;
         originalWidth = -1;
         originalHeight = -1;
      }

      public function saveOriginalContext():void {
         originalParent = parent;
         originalWidth = isNaN(percentWidth) ? width * 100 / parent.width : percentWidth;
         originalHeight = isNaN(percentHeight) ? height * 100 / parent.height : percentHeight;
         originalX = x;
         originalY = y;
      }

      public function restoreOriginalContext():void {
         if (originalParent && !originalParent.contains(this)) {
            originalParent.addChild(this);
         }
         percentWidth = originalWidth;
         percentHeight = originalHeight;
         x = originalX;
         y = originalY;
      }

      public function get dropEnabled():Boolean {
         if (tabBar) {
            return (tabBar as ViewTabBar).dropEnabled;
         }
         else {
            return _dropEnabled;
         }
      }

      public function set dropEnabled(value:Boolean):void {
         _dropEnabled = value;

         if (tabBar) {
            (tabBar as ViewTabBar).dropEnabled = value;
         }
      }

      override protected function createChildren():void {
         if (!tabBar) {
            // We're using our custom ViewTabBar class instead of TabBar
            tabBar = new ViewTabBar();
            tabBar.name = "tabBar";
            tabBar.focusEnabled = false;
            tabBar.styleName = this;
            (tabBar as ViewTabBar).dragEnabled = _dragEnabled;
            (tabBar as ViewTabBar).dropEnabled = _dropEnabled;

            tabBar.setStyle("borderStyle", "none");
            tabBar.setStyle("paddingTop", 0);
            tabBar.setStyle("paddingLeft", 0);
            tabBar.setStyle("paddingBottom", 0);
            tabBar.setStyle("paddingRight", 3);

            (tabBar as ViewTabBar).closeButtonVisiblePolicy = ViewTab.CLOSE_BUTTON_VISIBLE_ROLLOVER;
         }
         super.createChildren();

         if (!titleBar) {
            titleBar = new ViewWindowBar();
            titleBar.horizontalScrollPolicy = ScrollPolicy.OFF;
            rawChildren.addChild(titleBar);
            titleBar.addEventListener(MouseEvent.DOUBLE_CLICK, onClickMaximizeRestoreButton);
            titleBar.addEventListener(MouseEvent.CLICK, onClickTitleBar);
         }

         if (null == canvas) {
            canvas = new Canvas();
            canvas.styleName = this;
            canvas.setStyle("borderStyle", "none");
            canvas.setStyle("backgroundAlpha", 0);
            canvas.setStyle("paddingTop", 0);
            canvas.setStyle("paddingBottom", 0);
            canvas.horizontalScrollPolicy = ScrollPolicy.OFF;
            canvas.verticalScrollPolicy = ScrollPolicy.OFF;
            canvas.addChild(tabBar);
            titleBar.addChild(canvas);
         }

         if (!minimizeButton) {
            minimizeButton = new Button();
            minimizeButton.width = minimizeButton.height = 18;
            minimizeButton.styleName = "minimizeButton";
            minimizeButton.toolTip = "最小化";
            minimizeButton.addEventListener(MouseEvent.CLICK, onMinimize);
            titleBar.addChild(minimizeButton);
         }

         if (!maximizeButton) {
            maximizeButton = new Button();
            maximizeButton.width = maximizeButton.height = 18;
            maximizeButton.styleName = "maximizeButton";
            maximizeButton.toolTip = "最大化";
            maximizeButton.addEventListener(MouseEvent.CLICK, onClickMaximizeRestoreButton);
            titleBar.addChild(maximizeButton);
         }

         tabBar.addEventListener(ViewTabBar.TABS_REORDERED, tabsReordered);

         titleBar.doubleClickEnabled = true;
         titleBar.addEventListener(MouseEvent.DOUBLE_CLICK, onClickMaximizeRestoreButton);


         if (!dockProxy) {
            dockProxy = new Canvas();

            dockProxy.setStyle("backgroundAlpha", 0.4);
            dockProxy.setStyle("backgroundColor", 0xD4D0C8);
            dockProxy.setStyle("borderStyle", "solid");
            dockProxy.setStyle("borderThickness", 3);
            dockProxy.setStyle("borderColor", 0x58B299);

            dockProxy.visible = false;
            rawChildren.addChild(dockProxy);
         }

         if (!_menuCav) {
            _menuCav = new Canvas();
            _menuCav.visible = false;
            _menuCav.includeInLayout = false;
            _tabMenu = new TabMenu();
            _menuCav.addChild(_tabMenu);
            rawChildren.addChild(_menuCav);
         }

         invalidateSize();
      }

      private function onMouseDown(event:Event):void {
         ViewManager.getInstance().activeViewWindow = uid;
      }

      public function minimize():void {
         windowState = WINDOW_STATE_MINIMIZED;
         showControls = false;
      }

      public function set showControls(value:Boolean):void {
         _showControls = value;
         _showControlsChanged = true;
         invalidateProperties();
      }

      public function get closeButtonVisiblePolicy():String {
         return (tabBar as ViewTabBar).closeButtonVisiblePolicy;
      }

      public function set closeButtonVisiblePolicy(value:String):void {
         var old:String = (tabBar as ViewTabBar).closeButtonVisiblePolicy;
         (tabBar as ViewTabBar).closeButtonVisiblePolicy = value;
         if (old != value) {
            invalidateDisplayList();
         }
      }

      private function tabsReordered(event:Event):void {
      }

      private var forcedTabWidth:Number = -1;

      private var originalTabWidthStyle:Number = -1;

      private var _minTabWidth:Number = 60;


      override protected function commitProperties():void {
         super.commitProperties();

         if (_showControlsChanged) {
            includeInLayout = visible = _showControls;
            _showControlsChanged = false;
         }
      }

      override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
         super.updateDisplayList(unscaledWidth, unscaledHeight);

         minimizeButton.includeInLayout = maximizeButton.includeInLayout = true;
         var vm:EdgeMetrics = viewMetrics;
         var w:Number = unscaledWidth - vm.left - vm.right;

         var th:Number = tabBarHeight;
         var pw:Number = tabBar.getExplicitOrMeasuredWidth();

         var tabBarSpace:Number = w;

         tabBarSpace -= maximizeButton.width;
         tabBarSpace -= minimizeButton.width;

         if (pw > tabBarSpace) {
            var numTabs:Number = tabBar.numChildren;
            var tabSizeNeeded:Number = Math.max((tabBarSpace - getStyle("horizontalGap") * (numTabs - 1)) / numTabs, _minTabWidth);

            if (forcedTabWidth != tabSizeNeeded) {
               if (originalTabWidthStyle == -1) {
                  originalTabWidthStyle = getStyle("tabWidth");
               }

               forcedTabWidth = tabSizeNeeded;
               setStyle("tabWidth", forcedTabWidth);
               callLater(invalidateDisplayList);
               return;
            }
         }
         else {
            if (forcedTabWidth == -1 && getStyle("tabWidth") != originalTabWidthStyle && originalTabWidthStyle != -1) {
               if (getStyle("tabWidth") != undefined) {
                  if (isNaN(originalTabWidthStyle)) {
                     clearStyle("tabWidth");
                     tabBar.invalidateSize();
                     tabBar.invalidateDisplayList();
                  }
                  else {
                     setStyle("tabWidth", originalTabWidthStyle);
                  }

                  callLater(invalidateDisplayList);
               }
            }
            forcedTabWidth = -1;
         }

         if (forcedTabWidth != -1) {
            pw = (forcedTabWidth * tabBar.numChildren) + (getStyle("horizontalGap") * (tabBar.numChildren - 1));
         }
         var canvasWidth:Number = unscaledWidth;
         canvasWidth -= maximizeButton.width;
         canvasWidth -= minimizeButton.width;
         canvasWidth -= 3;
         canvas.width = canvasWidth;
         canvas.height = th;

         if (pw <= canvasWidth) {
            canvas.horizontalScrollPosition = 0;
         }

         tabBar.move(0, 0);
         tabBar.setActualSize(pw, th);

         titleBar.move(0, 0);
         titleBar.setActualSize(unscaledWidth, th);

         if (pw < canvasWidth) {
            switch (getStyle("horizontalAlign")) {
               case "left":
                  tabBar.move(0, tabBar.y);
                  break;
               case "right":
                  tabBar.move(unscaledWidth - tabBar.width, tabBar.y);
                  break;
               case "center":
                  tabBar.move((unscaledWidth - tabBar.width) / 2, tabBar.y);
            }
         }
      }

      protected function get tabBarHeight():Number {
         var tabHeight:Number = getStyle("tabHeight");

         if (isNaN(tabHeight))
            tabHeight = tabBar.getExplicitOrMeasuredHeight();

         return tabHeight;
      }

      private function tabChangedEvent(event:*):void {
         //callLater(ensureTabIsVisible);
         if (!selectedChild) {
            return;
         }
         var view:DockingView = selectedChild as DockingView;
         if (actived) {
            view.actived = true;
         }
         if (_lastSelectedView != view) {
            _lastSelectedView = view;
            _selectedViews.push(view);
         }

         onValueCommited();
      }

      private function onValueCommited(e:* = null):void {
         if (_tabMenu) {
            _tabMenu.selectedItems = [selectedChild];
            flexContextMenu = _tabMenu.menu;
         }
      }

      private function handleTabMouseOut(event:MouseEvent):void {
         if (getStageWindow().docking) {
            PopUpManager.removePopUp(dockProxy);
         }
      }

      private function handleTabMouseUp(event:MouseEvent):void {
         if (getStageWindow().docking && null != getStageWindow().dockView) {

            var view:DisplayObject = getStageWindow().dockView as DisplayObject

            var oldIndex:int = view.parent.getChildIndex(view);
            var newIndex:int = 0;

            ViewWindow(view.parent).removeChildAt(oldIndex);
            addChildAt(view, newIndex);

            //validate the visible items for the tab bar.
            //extended_TabBar(tabBar).validateVisibleTabs();

            getStageWindow().docking = false;
            getStageWindow().dockView = null;
            PopUpManager.removePopUp(dockProxy);
         }
      }

      private function handleTabMouseMove(event:MouseEvent):void {

      }

      private function handleTabMouseDown(event:MouseEvent):void {

      }

      private function getRealRect():Rectangle {
         var rectangle:Rectangle = new Rectangle();
         rectangle.width = width;
         rectangle.height = height;

         var point:Point = new Point();
         point.x = 0;
         point.y = 0; //- viewMetrics.top;
         point = localToGlobal(point);
         rectangle.x = point.x;
         rectangle.y = point.y;
         rectangle.y = point.y;
         return rectangle;
      }

      private function handleDragEnter(event:DragEvent):void {
         if (event.dragSource.hasFormat(ViewTab.FORMAT)) {
            var dropTarget:ViewWindow = ViewWindow(event.currentTarget);
            DragManager.acceptDragDrop(dropTarget);
         }
      }

      /**
       * draw indicator to show user where the tab
       * will be inserted
       **/
      private function onDragOver(event:DragEvent):void {
         if (event.dragSource.hasFormat(ViewTab.FORMAT)) {

            borderLayout = BorderLayout.CENTER;

            if (getStageWindow().docking) {

               var rectangle:Rectangle = getRealRect();
               var x:int = 0;
               var y:int = 0;

               var dockView:ViewTab = event.dragInitiator as ViewTab;
               var viewWindow:ViewWindow = dockView.getViewWindow();

               if (this == viewWindow && 1 == viewWindow.getChildren().length) {

               }
               else {
                  if (event.localX < rectangle.width / 4) {
                     borderLayout = BorderLayout.WEST;
                     rectangle.width /= 2;
                  }
                  else if (event.localX > rectangle.width * 3 / 4) {
                     borderLayout = BorderLayout.EAST;
                     x = rectangle.width / 2;
                     rectangle.width /= 2;
                  }
                  else {
                     if (event.localY < rectangle.height / 4) {
                        borderLayout = BorderLayout.NORTH;
                        rectangle.height /= 2;
                     }
                     else if (event.localY > rectangle.height * 3 / 4) {
                        borderLayout = BorderLayout.SOUTH;
                        y += rectangle.height / 2;
                        rectangle.height /= 2;
                     }
                  }
               }

               dockProxy.width = rectangle.width;
               dockProxy.height = rectangle.height;
               dockProxy.move(x, y);

               if (!dockProxy.visible) {
                  dockProxy.visible = true;
               }
            }
         }
      }

      private function onDragEnter(event:DragEvent):void {
         if (event.dragSource.hasFormat(ViewTab.FORMAT)) {
            var dropTarget:ViewWindow = ViewWindow(event.currentTarget);
            DragManager.acceptDragDrop(dropTarget);

            event.stopPropagation();
            event.preventDefault();

            var rectangle:Rectangle = getRealRect();

            dockProxy.width = rectangle.width;
            dockProxy.height = rectangle.height;
            dockProxy.move(0, 0);
            dockProxy.visible = true;

            getStageWindow().docking = true;
            getStageWindow().dockView = event.target as DisplayObject;
         }
      }

      private function onViewDocked(event:DockingEvent):void {
         if (numChildren == 0) {
            parent.removeChild(this);
         }
      }

      /**
       * clean up the drag drop indicator
       **/
      private function onDragExit(event:DragEvent):void {
         dockProxy.visible = false;
      }

      private function onDragDrop(event:DragEvent):void {
         dockProxy.visible = false;

         var dockEvent:DockingEvent = new DockingEvent(DockingEvent.DOCKED);
         dockEvent.viewTab = ViewTab(event.dragInitiator);
         dockEvent.viewWindow = this;

         dispatchEvent(dockEvent);
      }


      /**
       * when dragged (even between navigators) if the format is correct
       * move the tab to the new parent and location if the target is the
       * navigator then the new tab is inserted at location 0.
       **/
      private function handleTabDragDrop(event:DragEvent):void {
      }

      private function onDock(event:ItemClickEvent):void {
         event.stopPropagation();
         event.preventDefault();

         var rectangle:Rectangle = getRealRect();

         dockProxy.width = rectangle.width;
         dockProxy.height = rectangle.height;
         dockProxy.move(rectangle.x, rectangle.y);
         getStageWindow().docking = true;
         getStageWindow().dockView = event.target as DisplayObject;
      }


      private function onMinimize(event:MouseEvent):void {
         event.stopImmediatePropagation();
         if (windowState == WINDOW_STATE_DEFAULT) {
            saveOriginalContext();
         }
         dispatchEvent(new DockingEvent(DockingEvent.MINIMIZE));
         minimize();
      }

      public function fireRestore():void {
         showControls = true;
         maximizeButton.styleName = "maximizeButton";
         maximizeButton.toolTip = "最大化";
         windowState = WINDOW_STATE_DEFAULT;
         dispatchEvent(new DockingEvent(DockingEvent.RESTORE));
      }

      private function onClickMaximizeRestoreButton(event:MouseEvent = null):void {
         showControls = true;
         if (windowState == WINDOW_STATE_DEFAULT) {
            saveOriginalContext();
            dispatchEvent(new DockingEvent(DockingEvent.MAXIMIZE));
            // Call after the event is dispatched so the old state is still available.
            maximize();
            maximizeButton.styleName = "restoreButton";
            maximizeButton.toolTip = "恢复";
         }
         else {
            restoreOriginalContext();

            dispatchEvent(new DockingEvent(DockingEvent.RESTORE));
            // Set the state after the event is dispatched so the old state is still available.
            windowState = WINDOW_STATE_DEFAULT;
         }
      }

      public function maximize():void {
         windowState = WINDOW_STATE_MAXIMIZED;
         _maximize = true;
         _maximizeChanged = true;
      }

      private function onClickTitleBar(event:MouseEvent):void {
         if (windowState == WINDOW_STATE_MINIMIZED) {
            // Add the bottom border back in case we were minimized.
            onClickMaximizeRestoreButton();
         }
      }

      private function onViewClosed(event:ItemClickEvent):void {
         event.stopPropagation();
         event.preventDefault();

         closeView(event.index);
      }

      private function closeView(index:int):void {
         var view:DockingView = getChildAt(index) as DockingView;
         if (view && view.closable()) {
            ViewManager.getInstance().removeViewInstance(view, PerspectiveManager.getInstance().activePerspective);
            var object:DisplayObject = removeChildAt(index);
            object = null;
         }
      }

      private function onClose(event:*):void {
         closeView(selectedIndex);
      }

      private function onCloseOthers(event:*):void {
         var length:int = getChildren().length;
         for (var ii:int = length - 1; ii >= 0; ii--) {
            if (selectedIndex == ii) {
               continue;
            }
            closeView(ii);
         }
      }

      private function onCloseAll(event:*):void {
         var length:int = getChildren().length;
         for (var ii:int = length - 1; ii >= 0; ii--) {
            closeView(ii);
         }
      }

      override public function removeChild(item:DisplayObject):DisplayObject {
         var object:DisplayObject = super.removeChild(item);
         for (var ii:int = _selectedViews.length - 1; ii >= 0; ii --) {
            if (object == _selectedViews[ii]) {
               _selectedViews.splice(ii, 1);
            }
         }
         if (_selectedViews.length > 0) {
            selectedChild = _selectedViews[_selectedViews.length - 1];
         }
         return object;
      }

      override public function removeChildAt(index:int):DisplayObject {
         var object:DisplayObject = super.removeChildAt(index);
         var event:DockingEvent = new DockingEvent(DockingEvent.REMOVED, true, true);
         event.view = object as DockingView;
         event.viewWindow = this;
         dispatchEvent(event);
         return object;
      }

      override public function drawFocus(isFocused:Boolean):void {
         super.drawFocus(isFocused);
      }

      private function getStageWindow():StageWindow {
         var object:DisplayObject = this;
         while (!(object is StageWindow)) {
            object = object.parent;
         }
         return StageWindow(object);
      }

      public function get dragEnabled():Boolean {
         if (tabBar) {
            return (tabBar as ViewTabBar).dragEnabled;
         }
         else {
            return _dragEnabled;
         }
      }

      public function set dragEnabled(value:Boolean):void {
         _dragEnabled = value;

         if (tabBar) {
            (tabBar as ViewTabBar).dragEnabled = value;
         }
      }


      public function doClose():void {

      }

      public function doMinimize():void {

      }

      public function doMaximize():void {

      }

      public function doRestore():void {

      }

      public function doDetached():void {

      }

      public function doDock():void {

      }
   }
}